package modele.interfaces;

import appli.Loggable;
import controler.ModelControler;
import logs.LogLevelEnum;
import logs.LogTypesEnum;
import modele.parameters.SimulParameters;
import modele.parameters.SimulParametersNames;

public abstract class SimulationAbstract implements SimulationInterface,
		Loggable {

	protected ModelControler controler;
	protected boolean okToRunFromModel;
	protected String name;
	protected int stepsNbElapsed;
	protected int stepsNbLimit;
	protected boolean logSteps;
	protected SimulParameters params;

	protected abstract void doStep();

	protected abstract void logSteps();

	protected int speed;
	private boolean run;
	private boolean stepByStep;

	@Override
	public void init(ModelControler modelControler) {
		params = new SimulParameters();
		speed = 500;
		innerInit();

		stepsNbElapsed = 0;
		this.controler = modelControler;
		okToRunFromModel = true;
	}

	@Override
	public void run() {
		if (okToRunFromModel) {
			int i = 0;
			while (i < stepsNbLimit) {
				if ((stepByStep && run) || !stepByStep) {
					doStep();
					if (logSteps) {
						logSteps();
					}
					i++;
					if (1000 - speed > 0) {
						try {
							Thread.sleep(1000 - speed);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					if (stepByStep) {
						run = false;
					}
				}
			}
			okToRunFromModel = false;
		}
		logEndOfSimulation();
	}

	protected void logEndOfSimulation() {
		String log = " (" + this.getName() + ") " + "Terminated after "
				+ stepsNbElapsed + " steps";
		log(LogLevelEnum.INFO, LogTypesEnum.Simul, log);
	}

	@Override
	public void log(LogLevelEnum logLevel, LogTypesEnum LogType, String log) {
		controler.log(logLevel, LogType, log);
	}

	@Override
	public void triggerAStep() {
		if (!stepByStep) {
			stepByStep = true;
			run = true;
		} else
			run = true;
	}

	@Override
	public void setName() {
		setName(params.read(SimulParametersNames.NAME));
	}

	protected void innerInit() {
		params.load(SimulParametersNames.NAME, "Conway");
		params.load(SimulParametersNames.LOGSTEP, "false");
		params.load(SimulParametersNames.NBCASEX, "20");
		params.load(SimulParametersNames.NBCASEY, "20");
		params.load(SimulParametersNames.SPEED, "1000");
		params.load(SimulParametersNames.STEPNB, "150");
		params.load(SimulParametersNames.STEPBYSTEP, "true");
		logSteps = false;

		if (params.read(SimulParametersNames.LOGSTEP) == "true") {
			logSteps = true;
		}
		stepsNbLimit = Integer
				.valueOf(params.read(SimulParametersNames.STEPNB));
		speed = Integer.valueOf(params.read(SimulParametersNames.SPEED));
		run = false;
		stepByStep = true;
		if (params.read(SimulParametersNames.STEPBYSTEP) == "false") {
			stepByStep = false;
		}

		setName();
	}

	protected void setName(String name) {
		this.name = name;
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public void okToRun() {
		okToRunFromModel = true;
	}

	@Override
	public void runSimul() {
		run = true;

	}

	@Override
	public void pauseSimul() {
		run = false;

	}

	@Override
	public SimulParameters getParameters() {
		return params;
	}
}
